package com.fc.advbox.process.migrate;

import com.fc.advbox.process.migrate.option.None;
import com.fc.advbox.process.migrate.option.Option;
import com.fc.advbox.process.migrate.option.Some;

import java.util.Comparator;
import java.util.regex.Matcher;
import java.util.regex.Pattern;



/**
 * given a string which is assumed to be a "versioned" string which means it follows the format
 * of NNN_my_name_here, where NNN is numeric. it will sort them from first to last.
 * 
 * @author Chris
 */
public class VersionedStringComparator implements Comparator<String> {
    
    /**
     * the regex pattern used to test the versioned information.
     */
    public static final Pattern STRING_PATTERN = Pattern.compile("([0-9]+)[\\-\\_][a-z0-9\\_\\.-]+", Pattern.CASE_INSENSITIVE); 
    
    /**
     * indicates no version.
     */
    private static final Option<Integer> NO_OPTION = new None<Integer>();

    /**
     * compares two versioned strings in ascending order. strings which do not
     * fit into the format are appended onto the end.
     */
    @Override
    public int compare(String first, String second) {
        Matcher firstMatch  = STRING_PATTERN.matcher(first);
        Matcher secondMatch = STRING_PATTERN.matcher(second);
        
        if (firstMatch.matches() && secondMatch.matches()) {
            Integer firstVersion  = Integer.parseInt(firstMatch.group(1));
            Integer secondVersion = Integer.parseInt(secondMatch.group(1));
            
            return firstVersion.compareTo(secondVersion);
        } else {
            if (firstMatch.matches() && !secondMatch.matches()) return -1;
            if (firstMatch.matches() && !secondMatch.matches()) return 1;
            return first.compareTo(second);
        }
    }
    
    /**
     * given a string value, returns the versioning information.
     * 
     * @param versioned
     * @return the versioning information.
     */
    public static Option<Integer> getVersion( String versioned ) {
        Matcher matcher = STRING_PATTERN.matcher(versioned);
        if (matcher.matches()) {
            return new Some<Integer>(Integer.parseInt(matcher.group(1)));
        }
        
        return NO_OPTION;
    }

}
